﻿using System;
using System.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace Dragon.Library.Utility
{
    public sealed class ImageUtility
    {
        /// <summary>
        /// 获取指定mimeType的ImageCodecInfo
        /// </summary>
        private static ImageCodecInfo GetImageCodecInfo(string mimeType)
        {
            var codecInfo = ImageCodecInfo.GetImageEncoders();
            return codecInfo.FirstOrDefault(ici => ici.MimeType == mimeType);
        }

        /// <summary>
        ///  获取inputStream中的Bitmap对象
        /// </summary>
        public static Bitmap GetBitmapFromStream(Stream inputStream)
        {
            var bitmap = new Bitmap(inputStream);
            return bitmap;
        }

        /// <summary>
        /// 将Bitmap对象压缩为JPG图片类型
        /// </summary>
        /// <param name="bmp">源bitmap对象</param>
        /// <param name="quality">压缩质量，越大照片越清晰，推荐80</param>
        public static MemoryStream CompressAsJpg(Bitmap bmp, int quality)
        {
            var stream = new MemoryStream();
            var p = new EncoderParameter(Encoder.Quality, quality);
            var ps = new EncoderParameters(1);
            ps.Param[0] = p;
            bmp.Save(stream, GetImageCodecInfo("image/jpeg"), ps);
            bmp.Dispose();
            return stream;
        }

        /// <summary>
        /// 将inputStream中的对象压缩为JPG图片类型
        /// </summary>
        /// <param name="inputStream">源Stream对象</param>
        /// <param name="quality">压缩质量，越大照片越清晰，推荐80</param>
        public static MemoryStream CompressAsJpg(Stream inputStream, int quality)
        {
            var bmp = GetBitmapFromStream(inputStream);
            return CompressAsJpg(bmp, quality);
        }

        /// <summary>
        /// 生成缩略图（JPG 格式）
        /// </summary>
        /// <param name="imageByte">图片二进制</param>
        /// <param name="width">缩略图的宽</param>
        /// <param name="height">缩略图的高</param>
        public static byte[] ThumbAsJpg(byte[] imageByte, int width, int height)
        {
            Stream inputStream = new MemoryStream(imageByte);
            var imageStream = ThumbAsJpg(inputStream, width, height);
            var iByte = new byte[imageStream.Length];
            imageStream.Position = 0;
            imageStream.Read(iByte, 0, Convert.ToInt32(imageStream.Length));
            return iByte;
        }

        /// <summary>
        /// 生成缩略图（JPG 格式）
        /// </summary>
        /// <param name="inputStream">包含图片的Stream</param>
        /// <param name="width">缩略图的宽</param>
        /// <param name="height">缩略图的高</param>
        public static MemoryStream ThumbAsJpg(Stream inputStream, int width, int height)
        {
            var image = Image.FromStream(inputStream);
            if (image.Width == width && image.Height == height)
            {
                return CompressAsJpg(inputStream, 80);
            }
            int tWidth, tHeight, tLeft, tTop;
            double fScale = (double)height / width;
            if ((image.Width * fScale) > image.Height)
            {
                tWidth = width;
                tHeight = (int)((double)image.Height * tWidth / image.Width);
                tLeft = 0;
                tTop = (height - tHeight) / 2;
            }
            else
            {
                tHeight = height;
                tWidth = (int)((double)image.Width * tHeight / image.Height);
                tLeft = (width - tWidth) / 2;
                tTop = 0;

            }
            if (tLeft < 0) tLeft = 0;
            if (tTop < 0) tTop = 0;
            var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
            var graphics = Graphics.FromImage(bitmap);

            //可以在这里设置填充背景颜色
            graphics.Clear(Color.Transparent);
            graphics.DrawImage(image, new Rectangle(0, 0, width, height));
            //graphics.DrawImage(image, new Rectangle(tLeft, tTop, tWidth, tHeight));
            //graphics.DrawImage(image, new Rectangle(0, 0, tWidth, tHeight), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel);
            image.Dispose();

            try
            {
                return CompressAsJpg(bitmap, 80);
            }
            finally
            {
                bitmap.Dispose();
                graphics.Dispose();
            }
        }

        /// <summary>
        /// 将Bitmap对象裁剪为指定JPG文件
        /// </summary>
        /// <param name="bmp">源bmp对象</param>
        /// <param name="x">开始坐标x，单位：像素</param>
        /// <param name="y">开始坐标y，单位：像素</param>
        /// <param name="width">宽度：像素</param>
        /// <param name="height">高度：像素</param>
        public static MemoryStream CutAsJpg(Bitmap bmp, int x, int y, int width, int height)
        {
            var bmpW = bmp.Width;
            var bmpH = bmp.Height;

            if (x >= bmpW || y >= bmpH)
            {
                return CompressAsJpg(bmp, 80);
            }

            if (x + width > bmpW)
            {
                width = bmpW - x;
            }

            if (y + height > bmpH)
            {
                height = bmpH - y;
            }

            var bmpOut = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            var g = Graphics.FromImage(bmpOut);
            g.DrawImage(bmp, new Rectangle(0, 0, width, height), new Rectangle(x, y, width, height), GraphicsUnit.Pixel);
            g.Dispose();
            bmp.Dispose();
            return CompressAsJpg(bmpOut, 80);
        }

        /// <summary>
        /// 将Stream中的对象裁剪为指定JPG文件
        /// </summary>
        /// <param name="inputStream">源bmp对象</param>
        /// <param name="x">开始坐标x，单位：像素</param>
        /// <param name="y">开始坐标y，单位：像素</param>
        /// <param name="width">宽度：像素</param>
        /// <param name="height">高度：像素</param>
        public static MemoryStream CutAsJpg(Stream inputStream, int x, int y, int width, int height)
        {
            var bmp = GetBitmapFromStream(inputStream);
            return CutAsJpg(bmp, x, y, width, height);
        }

        #region 图片水印操作

        /// <summary>
        /// 给图片添加图片水印
        /// </summary>
        /// <param name="inputStream">包含要源图片的流</param>
        /// <param name="watermark">水印图片的流</param>
        /// <param name="mp">水印位置</param>
        public static MemoryStream AddPicWatermarkAsJpg(Stream inputStream, Stream watermark, MarkPosition mp)
        {
            var image = Image.FromStream(inputStream);
            var b = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
            var g = Graphics.FromImage(b);
            g.Clear(Color.White);
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.InterpolationMode = InterpolationMode.High;
            g.DrawImage(image, 0, 0, image.Width, image.Height);
            AddWatermarkImage(g, watermark, mp, image.Width, image.Height);
            try
            {
                return CompressAsJpg(b, 80);
            }
            finally
            {
                b.Dispose();
                image.Dispose();
            }
        }

        /// <summary>
        /// 给图片添加文字水印
        /// </summary>
        /// <param name="inputStream">包含要源图片的流</param>
        /// <param name="text">水印文字</param>
        /// <param name="mp">水印位置</param>
        public static MemoryStream AddTextWatermarkAsJpg(Stream inputStream, string text, MarkPosition mp)
        {
            var image = Image.FromStream(inputStream);
            var b = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
            var g = Graphics.FromImage(b);
            g.Clear(Color.White);
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.InterpolationMode = InterpolationMode.High;
            g.DrawImage(image, 0, 0, image.Width, image.Height);
            AddWatermarkText(g, text, mp, image.Width, image.Height);
            try
            {
                return CompressAsJpg(b, 80);
            }
            finally
            {
                b.Dispose();
                image.Dispose();
            }
        }

        /// <summary>
        /// 添加文字水印
        /// </summary>
        /// <param name="picture">要加水印的原图像</param>
        /// <param name="text">水印文字</param>
        /// <param name="mp">添加的位置</param>
        /// <param name="width">原图像的宽度</param>
        /// <param name="height">原图像的高度</param>
        private static void AddWatermarkText(Graphics picture, string text, MarkPosition mp, int width, int height)
        {
            var sizes = new[] { 16, 14, 12, 10, 8, 6, 4 };
            Font crFont = null;
            var crSize = new SizeF();
            for (var i = 0; i < 7; i++)
            {
                crFont = new Font("Arial", sizes[i], FontStyle.Bold);
                crSize = picture.MeasureString(text, crFont);
                if ((ushort)crSize.Width < (ushort)width)
                    break;
            }
            float xpos = 0;
            float ypos = 0;
            switch (mp)
            {
                case MarkPosition.MpLeftTop:
                    xpos = (width * (float).01) + (crSize.Width / 2);
                    ypos = height * (float).01;
                    break;
                case MarkPosition.MpRightTop:
                    xpos = (width * (float).99) - (crSize.Width / 2);
                    ypos = height * (float).01;
                    break;
                case MarkPosition.MpRightBottom:
                    xpos = (width * (float).99) - (crSize.Width / 2);
                    ypos = (height * (float).99) - crSize.Height;
                    break;
                case MarkPosition.MpLeftBottom:
                    xpos = (width * (float).01) + (crSize.Width / 2);
                    ypos = (height * (float).99) - crSize.Height;
                    break;
            }
            var strFormat = new StringFormat { Alignment = StringAlignment.Center };
            var semiTransBrush2 = new SolidBrush(Color.FromArgb(153, 0, 0, 0));
            picture.DrawString(text, crFont, semiTransBrush2, xpos + 1, ypos + 1, strFormat);
            var semiTransBrush = new SolidBrush(Color.FromArgb(153, 255, 255, 255));
            picture.DrawString(text, crFont, semiTransBrush, xpos, ypos, strFormat);
            semiTransBrush2.Dispose();
            semiTransBrush.Dispose();
        }

        /// <summary>
        /// 添加图片水印
        /// </summary>
        /// <param name="picture">要加水印的原图像</param>
        /// <param name="waterMark">水印文件的物理地址</param>
        /// <param name="mp">添加的位置</param>
        /// <param name="width">原图像的宽度</param>
        /// <param name="height">原图像的高度</param>
        private static void AddWatermarkImage(Graphics picture, Stream waterMark, MarkPosition mp, int width, int height)
        {
            Image watermark = new Bitmap(waterMark);
            var imageAttributes = new ImageAttributes();
            var colorMap = new ColorMap
            {
                OldColor = Color.FromArgb(255, 0, 255, 0),
                NewColor = Color.FromArgb(0, 0, 0, 0)
            };
            ColorMap[] remapTable = { colorMap };
            imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
            float[][] colorMatrixElements = {
                                                 new[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
                                                 new[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
                                                 new[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
                                                 new[] {0.0f,  0.0f,  0.0f,  0.3f, 0.0f},
                                                 new[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}
                                             };
            var colorMatrix = new ColorMatrix(colorMatrixElements);
            imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            var xpos = 0;
            var ypos = 0;
            double bl;
            if ((width > watermark.Width * 4) && (height > watermark.Height * 4))
            {
                bl = 1;
            }
            else if ((width > watermark.Width * 4) && (height < watermark.Height * 4))
            {
                bl = Convert.ToDouble(height / 4) / Convert.ToDouble(watermark.Height);
            }
            else
                if ((width < watermark.Width * 4) && (height > watermark.Height * 4))
                {
                    bl = Convert.ToDouble(width / 4) / Convert.ToDouble(watermark.Width);
                }
                else
                {
                    if ((width * watermark.Height) > (height * watermark.Width))
                    {
                        bl = Convert.ToDouble(height / 4) / Convert.ToDouble(watermark.Height);
                    }
                    else
                    {
                        bl = Convert.ToDouble(width / 4) / Convert.ToDouble(watermark.Width);
                    }
                }
            var watermarkWidth = Convert.ToInt32(watermark.Width * bl);
            var watermarkHeight = Convert.ToInt32(watermark.Height * bl);
            switch (mp)
            {
                case MarkPosition.MpLeftTop:
                    xpos = 10;
                    ypos = 10;
                    break;
                case MarkPosition.MpRightTop:
                    xpos = width - watermarkWidth - 10;
                    ypos = 10;
                    break;
                case MarkPosition.MpRightBottom:
                    xpos = width - watermarkWidth - 10;
                    ypos = height - watermarkHeight - 10;
                    break;
                case MarkPosition.MpLeftBottom:
                    xpos = 10;
                    ypos = height - watermarkHeight - 10;
                    break;
            }
            picture.DrawImage(watermark, new Rectangle(xpos, ypos, watermarkWidth, watermarkHeight), 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel, imageAttributes);
            watermark.Dispose();
            imageAttributes.Dispose();
        }

        /// <summary>
        /// 水印的位置
        /// </summary>
        public enum MarkPosition
        {
            /// <summary>
            /// 左上角
            /// </summary>
            MpLeftTop,
            /// <summary>
            /// 左下角
            /// </summary>
            MpLeftBottom,
            /// <summary>
            /// 右上角
            /// </summary>
            MpRightTop,
            /// <summary>
            /// 右下角
            /// </summary>
            MpRightBottom
        }

        #endregion



    }
}
